package idle;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;

import java.util.concurrent.TimeUnit;

/**
 * @author LONG
 * @date 2018/1/9 11:18
 */
@ChannelHandler.Sharable
public abstract class ConnectionWatcherAbstract extends ChannelInboundHandlerAdapter implements TimerTask {

    protected final HashedWheelTimer timer = new HashedWheelTimer();
    private final Bootstrap bootstrap;
    private final int port;
    private final String host;
    private volatile boolean reconnect = true;
    private int attempts;
    private final int retry = 12;

    public ConnectionWatcherAbstract(Bootstrap bootstrap, String host, int port, boolean reconnect) {
        this.bootstrap = bootstrap;
        this.port = port;
        this.host = host;
        this.reconnect = reconnect;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("当前链路已经激活了，重连尝试次数重新置为 0");
        //重连次数清0
        attempts = 0;
        ctx.fireChannelActive();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("链接关闭");
        if (reconnect) {
            System.out.println("进行重连");
            if (attempts < retry) {
                attempts++;
                //重连的间隔时间会越来越长
                int timeout = 200 << attempts;
                System.out.println(timeout);
                timer.newTimeout(this, timeout, TimeUnit.MILLISECONDS);
            } else {
                //shutdownGracefully();
            }
        }
        ctx.fireChannelInactive();
    }

    @Override
    public void run(Timeout timeout) throws Exception {
        ChannelFuture future;
        //bootstrap已经初始化好了，只需要将handler填入就可以了
        synchronized (bootstrap) {
            bootstrap.handler(new ChannelInitializer<Channel>() {
                @Override
                protected void initChannel(Channel ch) throws Exception {
                    ch.pipeline().addLast(handlers());
                }
            });
            future = bootstrap.connect(host, port);
        }

        //future对象
        future.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                boolean succeed = future.isSuccess();
                //如果重连失败，则调用ChannelInactive方法，再次出发重连事件，一直尝试12次，如果失败则不再重连
                if (!succeed) {
                    System.out.println("重连失败");
                    future.channel().pipeline().fireChannelInactive();
                } else {
                    System.out.println("重连成功");
                }
            }
        });
    }

    public abstract ChannelHandler[] handlers();

}
